﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace Sublimation
{
    public class WorldProperties : GameComponent
    {
        protected Factory factory;
        public Factory Factory
        {
            get
            {
                return factory;
            }
        }
        protected SpriteBatch spriteBatch;
        public SpriteBatch SpriteBatch
        {
            get
            {
                return spriteBatch;
            }
        }
        protected GameMap map;
        public GameMap Map
        {
            get { return this.map; }
            set { this.map = value; }
        }

        public static int MAX_PLAYERS = 4;
        protected int playerCount;
        public int PlayerCount
        {
            get { return playerCount; }
            set { playerCount =Math.Min(value, MAX_PLAYERS); }
        }

        protected Player[] players;
        public Player[] Players
        {
            get { return this.players; }
            set { this.players = value; }
        }

        public static int MAX_ENEMIES = 100;
        protected List<EnemyUnit> enemies;
        public List<EnemyUnit> Enemies
        {
            get { return this.enemies; }
            set { enemies = value; }
        }

        public Rectangle WorldBounds()
        {
            return this.map.WorldBounds;
        }

        public virtual void GeneratePlayers()
        {
            Players = new Player[PlayerCount];
            for (int i = 0; i < PlayerCount; i++)
            {
                Players[i] = new Player(this);
            }
        }

        public void StartGame()
        {
            GeneratePlayers();
        }

        protected bool gameOver = false;
        public bool isGameOver() { return gameOver; }
        public void EndGame()
        {
            // TODO: whatever needs to be done when the game is over
            gameOver = true;
            System.Diagnostics.Debug.WriteLine("Game over man, game over!");
        }

        public WorldProperties(Game game):base(game)
        {
            spriteBatch = new SpriteBatch(game.GraphicsDevice);
            Game.Components.Add(this);
            this.Enemies = new List<EnemyUnit>();
            PlayerCount = 1; // just a default to make sure.. not really necessary
            factory = new Factory();

            // Update last for cleanup etc
            UpdateOrder = 100;
        }

        protected int enemyCount = 0;
        public int EnemyCount
        {
            get { return this.enemyCount; }
            set { this.enemyCount = value; }
        }

        protected Random random = new Random();
        public Random Random
        {
            get { return this.random; }
        }

        protected List<GameObject> garbage = new List<GameObject>();
        public void addGarbage(GameObject trash)
        {
            garbage.Add(trash);
        }

        private double lastEnemySpawnMillis = 0;
        private int garbageCollectTickCount = 0;
        private const int TICKS_BETWEEN_COLLECTS = 30;
        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            // Garbage collection for the world
            //XXX: incase of performance could maybe do this less
            if (!gameTime.IsRunningSlowly && garbageCollectTickCount <= 0)
            {
                foreach (GameObject trash in garbage)
                {
                    trash.GarbageCollect();
                }
                garbage.Clear();
                garbageCollectTickCount = TICKS_BETWEEN_COLLECTS;
            }
            garbageCollectTickCount--;

            // handle enemy spawning every half second
            // TODO: update this from my notes, this is not at all the way it will be eventually :)
            if (gameTime.TotalGameTime.TotalMilliseconds - lastEnemySpawnMillis >= 500)
            {
                lastEnemySpawnMillis = gameTime.TotalGameTime.TotalMilliseconds;
                
                // work out the current number of enemies to have as the max
                const int TIME_UNTIL_MAX_UNITS_SECONDS = 1200; // 20 mins
                int currentMaxEnemies = (int) Math.Min(
                    (MAX_ENEMIES * Math.Log((gameTime.TotalGameTime.TotalSeconds * (MathHelper.E + 1) / TIME_UNTIL_MAX_UNITS_SECONDS) + 1))
                    , MAX_ENEMIES);

                //TODO: remove temp
                //currentMaxEnemies = 100;

                // now we know how many there could be - let's spawn some more now if we can
                // XXX: maybe the max enemies should determine how many spawn per second and this check should be against the MAX_ENEMIES
                // this way killing more doesn't make more spawn
                // on the other hand its an intersting tacting to try to slow them down rather than killing
                if (EnemyCount < currentMaxEnemies)
                {
                    // for each one we COULD spawn
                    for (int i = 0; i < (currentMaxEnemies - enemyCount); i++)
                    {
                        // give it a chance to spawn as nothing or as one of the unit types
                        //TODO: unit types
                        if(Random.NextDouble() > 0.25d) {
                            // spawn something
                            Enemies.Add(new EnemyUnit(this));
                            enemyCount++;
                        }
                    }
                }
            }
        }
    }
}
